#pragma once
#include <atomic>
#include <chrono>
#include <functional>
#include <iostream>
#include <map>
#include <mosquitto.h>
#include <mutex>
#include <string>
#include <thread>

namespace mqtt {

/**
 * @brief 通用 MQTT 客户端类
 *
 * 功能：
 *  - 发布任意主题消息
 *  - 订阅多个主题
 *  - 按主题回调消息，也可设置默认回调
 *  - 自动重连（异步，非阻塞）
 *  - 支持用户名/密码认证
 *  - 线程安全
 */
class MQTTClient {
public:
  using MessageCallback =
      std::function<void(const std::string &topic, const std::string &payload)>;

  /**
   * @brief 构造函数
   * @param baseClientId 客户端基础ID，用于生成唯一客户端ID
   * @param cleanSession 是否使用干净会话（true：不保留上次会话信息）
   */
  MQTTClient(const std::string &baseClientId = "", bool cleanSession = true);

  /**
   * @brief 析构函数
   *
   * 断开连接并清理 mosquitto 库资源
   */
  ~MQTTClient();

  /**
   * @brief 连接到 MQTT Broker
   * @param host broker IP 或域名
   * @param port broker 端口
   * @param username 用户名（可选）
   * @param password 密码（可选）
   * @param qos 默认 QoS 值
   * @param keepalive 心跳间隔（秒）
   *
   * 异步连接 broker，并允许自动重连
   */
  void connect(const std::string &host, uint16_t port,
               const std::string &username = "",
               const std::string &password = "", uint8_t qos = 1,
               int keepalive = 60);

  /**
   * @brief 断开与 broker 的连接
   */
  void disconnect();

  /**
   * @brief 发布消息到指定主题
   * @param topic 主题
   * @param payload 消息内容
   * @param qos 消息 QoS，1 表示使用默认值
   * @return MOSQ_ERR_SUCCESS 或错误码
   */
  int publish(const std::string &topic, const std::string &payload,
              int qos = 1);

  /**
   * @brief 订阅主题
   * @param topic 要订阅的主题
   * @param qos QoS，1 表示使用默认值
   * @param cb 消息回调函数（可选）
   * @return true 成功，false 失败
   */
  bool subscribe(const std::string &topic, int qos = 1,
                 MessageCallback cb = nullptr);

  /**
   * @brief 为指定主题设置回调函数
   * @param topic 主题
   * @param cb 回调函数
   */
  void set_message_callback(const std::string &topic, MessageCallback cb);

  /**
   * @brief 设置默认回调函数
   * @param cb 回调函数
   */
  void set_default_callback(MessageCallback cb);

  /**
   * @brief 检查客户端是否已连接
   * @return true 已连接，false 未连接
   */
  bool isConnected() const;

private:
  /**
   * @brief 生成客户端唯一ID
   * @return 客户端ID字符串
   */
  std::string generateClientId() const;

  /**
   * @brief 获取格式化当前时间（年月日时分秒毫秒）
   * @return 格式化字符串
   */
  static std::string getFormattedCurrentDateTime();

  /**
   * @brief 内部连接 broker
   *
   * 创建 mosquitto 实例，设置回调，启动异步连接和消息循环
   */
  void internalConnect();

  /**
   * @brief 处理 mosquitto 错误码
   * @param code mosquitto 错误码
   */
  void handleMosquittoError(int code);

  /**
   * @brief 启动重连线程（异步）
   */
  void startReconnect();

  /**
   * @brief 连接回调
   */
  static void onConnect(struct mosquitto *, void *obj, int rc);

  /**
   * @brief 断开回调
   */
  static void onDisconnect(struct mosquitto *, void *obj, int rc);

  /**
   * @brief 静态消息回调，用于 mosquitto API
   */
  static void onMessageStatic(struct mosquitto *, void *obj,
                              const struct mosquitto_message *msg);

  /**
   * @brief 消息处理
   * @param msg 消息结构体
   *
   * 根据主题调用对应回调函数，若未找到主题回调则调用默认回调
   */
  void onMessage(const struct mosquitto_message *msg);

private:
  struct mosquitto *m_mosq;            ///< mosquitto 客户端实例指针
  std::atomic<bool> m_connected;       ///< 当前连接状态
  std::atomic<bool> m_shouldReconnect; ///< 是否允许自动重连
  bool m_cleanSession;                 ///< 是否使用干净会话
  std::string m_baseClientId;          ///< 用户提供的基础客户端ID
  std::string m_clientId;              ///< 实际使用的客户端ID（唯一）

  std::string m_host;     ///< broker IP 或域名
  uint16_t m_port;        ///< broker 端口
  std::string m_username; ///< 登录用户名
  std::string m_password; ///< 登录密码
  uint8_t m_qos;          ///< 默认 QoS
  int m_keepalive;        ///< 心跳间隔（秒）

  mutable std::mutex m_mutex; ///< 线程锁，保证线程安全
  std::map<std::string, MessageCallback> m_topic_callbacks; ///< 主题回调映射
  MessageCallback m_default_cb;                             ///< 默认回调函数
};

} // namespace mqtt
